module Timeline where

import Lens.Micro (Lens', (^.), (&), (%~), (<&>))
import qualified Data.Time as Time
import qualified Data.Text as Text
import Data.Maybe (catMaybes)
import Data.List (sortBy)
import Text.Printf (printf)
import Brick.Types (Widget)
import qualified Brick.Widgets.Center as C
import Brick.Widgets.Core
  ( str
  , txt
  , vLimit
  , vBox
  , hBox
  )

import qualified DataType as DT

data HourMinute = HourMinute Int Int
                deriving Eq

instance Ord HourMinute where
  compare (HourMinute h1 m1) (HourMinute h2 m2) = case compare h1 h2 of
    EQ -> compare m1 m2
    GT -> GT
    LT -> LT

instance Show HourMinute where
  show (HourMinute h m) = printf "%02d" h <> ":" <> printf "%02d" m

timeToHourMinute :: Time.LocalTime -> HourMinute
timeToHourMinute (Time.LocalTime _ t) = HourMinute h m where
  h = Time.todHour t
  m = Time.todMin t

-- | Ticks on timeline
majorTicks :: [HourMinute]
majorTicks = [ HourMinute 9 0
             , HourMinute 12 0
             , HourMinute 15 0
             , HourMinute 18 0
             , HourMinute 21 0
             ]

data LineItem = ScheduleLine HourMinute DT.Task
              | DeadlineLine HourMinute DT.Task
              | MajorTick HourMinute
              | NowTick HourMinute

class ToLineItem a where
  toLineItem :: a -> [LineItem]

instance ToLineItem HourMinute where
  toLineItem t = pure $ MajorTick t

instance ToLineItem Time.LocalTime where
  toLineItem t = pure . NowTick . timeToHourMinute $ t

instance ToLineItem DT.Task where
  toLineItem task = catMaybes [scheduleM, deadlineM] where
    scheduleM = task^.DT.scheduleAtL <&> \t -> ScheduleLine (timeToHourMinute t) task
    deadlineM = task^.DT.deadlineAtL <&> \t -> DeadlineLine (timeToHourMinute t) task

class Drawable w where
  draw :: w -> Widget n

getItemTime :: LineItem -> HourMinute
getItemTime (ScheduleLine t _) = t
getItemTime (DeadlineLine t _) = t
getItemTime (MajorTick t) = t
getItemTime (NowTick t) = t

eqByTime :: LineItem -> LineItem -> Bool
eqByTime a b = getItemTime a == getItemTime b

ordByTime :: LineItem -> LineItem -> Ordering
ordByTime a b = compare (getItemTime a) (getItemTime b)

drawTaskLine :: String -> HourMinute -> DT.Task -> Widget n
drawTaskLine label time task =
  hBox [ str $ show time
       , str " "
       , str label
       , str urgent
       , str important
       , str " "
       , txt $ task^.DT.nameL
       ] where
  urgent = if task^.DT.urgentL then "U" else " "
  important = if task^.DT.importantL then "I" else " "

instance Drawable LineItem where
  draw (MajorTick t) = str $ show t <> " ----------------------"
  draw (NowTick t) = str $ show t <> " *********NOW**********"
  draw (ScheduleLine t task) = drawTaskLine "[S]" t task
  draw (DeadlineLine t task) = drawTaskLine "[D]" t task

-- | Sort and make unique timeline items
arangeItems :: Time.LocalTime -> [DT.Task] -> [LineItem]
arangeItems time tasks = sortBy ordByTime items where
  items = (toLineItem =<< tasks) <>
          (toLineItem time) <>
          (toLineItem =<< majorTicks)

drawTimeline :: Time.LocalTime -> [DT.Task] -> Widget n
drawTimeline time tasks = vBox $ draw <$> arangeItems time tasks

drawStatisticBoard :: Time.LocalTime -> [DT.Task] -> Widget n
drawStatisticBoard time tasks = ui where
  ui = vLimit 20 $
       C.hCenter $
       C.vCenter $
       drawTimeline time tasks
